package bdhub.littletail.lib.net.request;

import android.util.Config;
import android.util.Log;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import bdhub.littletail.app.config.NetworkConfig;
import bdhub.littletail.lib.net.listener.OnResponseListener;
import bdhub.littletail.lib.net.volley.AuthFailureError;
import bdhub.littletail.lib.net.volley.BusinessError;
import bdhub.littletail.lib.net.volley.Request;
import bdhub.littletail.lib.net.volley.TimeoutError;
import bdhub.littletail.lib.net.volley.VolleyError;

/**
 * Created by Freddy on 2016/2/23.
 * chenshichao@outlook.com
 * 基于Vollery的自定义Request，如StringRequest、JsonRequest等
 */
public abstract class CustomRequest<T> extends Request<T> {

    private final String TAG = CustomRequest.class.getSimpleName();

    /**
     * 编码格式
     */
    private static final String PARAMS_ENCODING = "UTF-8";

    /**
     * HTTP请求超时时间
     */
    private static final int TIMEOUT = 30000;

    /**
     * 网络请求回调类
     */
    private OnResponseListener<T> mOnResponseListener;

    /**
     * 参数
     */
    private Object mParams;

    /**
     * 计时器，用于计算是否请求超时
     */
    private Timer mTimer;

    public CustomRequest(String path, OnResponseListener<T> listener) {
        this(path, null, listener);
    }

    public CustomRequest(String path, Object params, OnResponseListener<T> listener) {
        super(Method.POST, NetworkConfig.SERVER_BASE_URL + path, null);
//        super(Method.POST, path, null);
        this.mOnResponseListener = listener;
        this.mParams = params;
        if(Config.DEBUG) {
            Log.v(TAG, path);
            if(null != params) {
                Log.v(TAG, "params：" + params.toString());
            }
        }
        mTimer = new Timer();
        mTimer.schedule(new TimerTask() {

            @Override
            public void run() {
                Log.v(TAG, "request timeout：" + getUrl());
                deliveTimeoutError();
            }
        }, TIMEOUT);
    }

    @Override
    public byte[] getBody() throws AuthFailureError {
        if(null != mParams) {
            JSONObject jsonObject;
            if(mParams instanceof JSONObject) {
                jsonObject = (JSONObject) mParams;
            } else {
                jsonObject = JSONObject.parseObject(JSONObject.toJSONString(
                        mParams,
                        SerializerFeature.DisableCircularReferenceDetect),
                        Feature.DisableCircularReferenceDetect);
            }

            StringBuilder encodeParams = new StringBuilder();
            try {
                for(Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                    if(null != entry.getValue()) {
                        encodeParams.append(URLEncoder.encode(entry.getKey(), PARAMS_ENCODING));
                        encodeParams.append("=");
                        encodeParams.append(URLEncoder.encode(entry.getValue().toString(), PARAMS_ENCODING));
                        encodeParams.append("&");
                    }
                }
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException("Encoding not supported：" + PARAMS_ENCODING, e);
            }
            return encodeParams.toString().getBytes();
        }
        return null;
    }

    /**
     * 超时错误
     */
    private void deliveTimeoutError() {
        cancel();
        if(null != mOnResponseListener) {
            mOnResponseListener.onNetworkError(new TimeoutError());
            mOnResponseListener.onFinished();
        }
    }

    /**
     * 网络请求或业务逻辑返回错误
     * @param error Error details
     */
    @Override
    public void deliverError(VolleyError error) {
        mTimer.cancel();

        if(error instanceof BusinessError) {
            Log.e(TAG, error.getMessage());
            if(null != mOnResponseListener) {
                mOnResponseListener.onBunsinessFailed((BusinessError) error);
            }
        } else {
            error.printStackTrace();
            if(null != mOnResponseListener) {
                mOnResponseListener.onNetworkError(error);
            }
        }

        if(null != mOnResponseListener) {
            try {
                mOnResponseListener.onFinished();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void deliverResponse(T response) {
        mTimer.cancel();
        if(null != mOnResponseListener) {
            try {
                mOnResponseListener.onBusinessSuccessed(response);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                mOnResponseListener.onFinished();
            }
        }
        cancel();
    }
}
